package com.ruoyi.framework.extendsions.security.filter;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.framework.extendsions.security.token.SmsCodeAuthenticationToken;
import io.jsonwebtoken.lang.Assert;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import reactor.util.annotation.NonNull;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
import java.util.stream.Collectors;

public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    private final ObjectMapper objectMapper = new ObjectMapper();

    // path 例如 "/app/reg-and-login"
    public SmsCodeAuthenticationFilter(String path, AuthenticationManager authenticationManager) {
        super(new AntPathRequestMatcher(path, "POST"));
        Assert.notNull(authenticationManager, "authenticationManager must be specified");
        setAuthenticationManager(authenticationManager);
    }

    @Override
    public Authentication attemptAuthentication(@NonNull HttpServletRequest request,
                                                @NonNull HttpServletResponse response) throws AuthenticationException, IOException {
        // 兼容 form-data 和 application/json 两种情况
        String phone = request.getParameter("phone");

        if ((phone == null || phone.isEmpty()) && "application/json".equalsIgnoreCase(request.getContentType())) {
            String body = request.getReader().lines().collect(Collectors.joining());
            if (body != null && !body.isEmpty()) {
                JsonNode node = objectMapper.readTree(body);
                if (node.has("phone")) phone = node.get("phone").asText();
            }
        }

        if (phone == null) phone = "";

        SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(phone.trim());
        setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }

    protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }
}
